package roborally.model;
import be.kuleuven.cs.som.annotate.*;
import roborally.model.interfaces.*;

/**
 * @Invar	|isValidWeight(getWeight())
 * @Extends	Element
 * @Implements Comparable<Item>
 * @Implements Terminatable
 */
public abstract class Item extends Element implements Comparable<Item>, Terminatable {

	//CONSTRUCTOR
	/**
	 * Constructor of an Item object.
	 * @param weight
	 * @post new.myField = null
	 * @effect if(!isValidWeight(weight)) then setWeight(0)
	 * @effect if(isValidWeight(weight)) then setWeight(weight)
	 * @note Weight is handled in a total way
	 */
	@Model
	protected Item(int weight)
	{
		super();
		if(!isValidWeight(weight)) setWeight(0);
		else setWeight(weight);
	}
	/**
	 * Default constructor of an Item object.
	 * @effect this(WEIGHT_DEFAULT)
	 */
	@Model
	protected Item(){ this(WEIGHT_DEFAULT); }
	
	//WEIGHT
	
	/**
	 * Returns the weight of an Item object
	 * @return this.weight
	 */
	@Basic @Raw
	public int getWeight(){	return this.weight; }
	
	/**
	 * Sets the weight of an Item to weight
	 * @param weight
	 * @effect getWeight() == weight
	 */
	@Basic @Raw
	public void setWeight(int weight){ this.weight = weight; }
	
	/**
	 * The weight of an Item object is always greater than or equal to zero
	 * @param weight
	 * @return Returns true if the weight of the Item object is greater than or equal to zero, returns false ohterwise
	 * 	      |result == (weight >= 0)
	 */
	@Raw
	public static boolean isValidWeight(int weight){ return weight >= 0; }
	
	/**
	 * A final static integer expressing the default weight of an Item
	 */
	public final static int WEIGHT_DEFAULT = 500;
	
	/**
	 * An integer variable indicating the weight of an Item object in gram (g)
	 */
	private int weight; //weight expressed in gram (g)
	
	//other overwrites
	/**
	 * Returns a boolean indicating whether or not this item can be placed on the same field as the given element.
	 * @return if( otherElement instanceof Item || otherElement instanceof Robot) then result == true
	 * @return if(	!(otherElement instanceof Item && otherElement instanceof Robot) ) then result == otherElement.canHaveSameFieldAs(this) 
	 */
	@Override @Raw
	public boolean canHaveSameFieldAs(Element otherElement){
		if(otherElement instanceof Item || otherElement instanceof Robot)
			return true;
		return otherElement.canHaveSameFieldAs(this);
	}
	
	//Compare (so that we can compare items for sorting purposes)
	/**
	 * Method useful for comparing the weight of an Item object with another Item object
	 * @param other
	 * 			The other Item object
	 * @return Returns -1 if this.getWeight() > other.getWeight(), returns 1 if this.getWeight() < other.getWeight(), returns 0 otherwise
	 * @note This class has a natural ordering that is inconsistent with equals.
	 */
	@Override
	public int compareTo(Item other){
		if(this.getWeight() < other.getWeight()) return 1;
		if(this.getWeight() > other.getWeight()) return -1;
		else return 0;
	}
	
}
